package app

import (
	"gitee.com/huangxinbo/xcas/asynq/handle"
	"gitee.com/huangxinbo/xcas/asynq/middleware"
	"gitee.com/huangxinbo/xcas/internal/app/base"
	"gitee.com/huangxinbo/xcas/internal/asynq_handle_routes"
	"gitee.com/huangxinbo/xcas/internal/config"
	"gitee.com/huangxinbo/xcas/internal/dao"
	"gitee.com/huangxinbo/xcas/internal/service"
	"gitee.com/huangxinbo/xcas/pkg"
	"gitee.com/huangxinbo/xcas/pkg/asynq_instance"
	"gitee.com/huangxinbo/xcas/pkg/db"
	"gitee.com/huangxinbo/xcas/pkg/i18n"
	"gitee.com/huangxinbo/xcas/pkg/logger"
	"gitee.com/huangxinbo/xcas/pkg/mail"
	"gitee.com/huangxinbo/xcas/pkg/redis_client"
	"github.com/hibiken/asynq"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

type App struct {
	Config      *config.Config
	DbInstance  *gorm.DB
	Redis       *redis.Client
	I18n        *i18n.I18n
	Logger      *logger.Logger
	AsynqServer *asynq.Server
	AsynqClient *asynq.Client

	DAO     *dao.DAO
	Service *service.Service
	Handle  *handle.Handle
}

func NewApp() (*App, error) {
	app := &App{}

	// Initialize configuration
	cfg := config.InitConfig()
	app.Config = cfg

	// Initialize logger
	log, err := logger.NewLogger("asynq", *cfg)
	if err != nil {
		return nil, err
	}
	app.Logger = log

	// Initialize database
	database, err := db.NewDB(cfg, log)
	if err != nil {
		log.Error("DB connection failed, error: " + err.Error())
		return nil, err
	}
	app.DbInstance = database

	// Initialize Redis
	redisClient, err := redis_client.NewRedis(cfg, log)
	if err != nil {
		log.Error("Redis connection failed, error: " + err.Error())
		return nil, err
	} else {
		app.Redis = redisClient
	}

	// Initialize i18n
	i18n := i18n.NewI18n(pkg.GetEnvString("I18N.LOCALES.PATH", "locales") + "/asynq")
	app.I18n = i18n

	// Initialize mail service
	mail := mail.NewMail(app.Logger, app.Config, app.I18n)

	app.AsynqClient = asynq_instance.NewAsnyqClient(cfg.Redis, cfg.Asynq)
	app.AsynqServer = asynq_instance.NewAsnyqServer(cfg.Redis, cfg.Asynq)

	base := base.NewBase(cfg, log, i18n, database, redisClient, app.AsynqServer, app.AsynqClient, mail)

	// Initialize DAO
	app.DAO = dao.NewDAO(base)

	// Initialize Service
	app.Service = service.NewService(base, app.DAO)

	// Initialize Controller
	app.Handle = handle.NewHandle(base, app.Service)

	return app, nil
}

func NewAsynqMux(app *App) *asynq.ServeMux {
	// Register routes
	mux := asynq.NewServeMux()
	mux.HandleFunc(string(asynq_handle_routes.RouteEmailRegisterVerification), app.Handle.EmailHandle.HandleEmailRegisterVerification)
	mux.HandleFunc(string(asynq_handle_routes.RouteEmailForgotVerification), app.Handle.EmailHandle.HandleEmailForgotVerification)
	return mux
}

func (app *App) Run() error {
	mux := NewAsynqMux(app)
	m := middleware.NewMiddleware(app.Logger, app.I18n)
	handler := m.Middleware(mux)
	return app.AsynqServer.Run(handler)
}

func (app *App) Shutdown() error {
	// Shutdown server
	if app.AsynqClient != nil {
		app.AsynqClient.Close()
	}
	if app.AsynqServer != nil {
		app.AsynqServer.Shutdown()
		app.AsynqServer.Stop()
	}

	// Close other resources
	return app.Close()
}

func (app *App) Close() error {
	// Close database connections and other resources
	if app.DbInstance != nil {
		sqlDB, _ := app.DbInstance.DB()
		return sqlDB.Close()
	}
	if app.Redis != nil {
		return app.Redis.Close()
	}
	if app.Logger != nil {
		return app.Logger.Logger.Sync()
	}
	return nil
}
